package com.wrxdz.start.surfaceviewt.surfview;


import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.Toast;

import com.wrxdz.start.surfaceviewt.R;
import com.wrxdz.start.surfaceviewt.surfview.utils.Utils;
import com.wrxdz.start.surfaceviewt.surfview.utils.PukeClickUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author dz
 * 基于 CSDN Bison 二次编写
 *
 * <p>
 * 经验:
 * 了解SurfaceView基础使用
 * 了解线程基础使用
 */
@SuppressLint("ViewConstructor")
public class GameView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private static final String TAG = "GameView";
    private Bitmap sourceBitmap = null;// 扑克图片来源
    private Bitmap backgroundDesk = null;// 牌桌背景
    private Bitmap backgroundPuke = null;// 扑克背面
    private Bitmap sourcePersonBitmap = null;//人物图片来源
    private int pukeWidth = 0;// 扑克的宽
    private int pukeHeight = 0;// 扑克的高
    private int deskWidth = 0;// 牌桌的宽
    private int deskHeight = 0;// 牌桌的高
    private int personWidth = 0;//人物的宽
    private int personHeight = 0;//人物的高
    private int left_;// 我自己首张牌左距离
    private float a = 0.68f;//扑克牌重叠比例
    private boolean isDrawing = false;//标志位
    private final SurfaceHolder holder;
    private int touchPukeResult = -1;//手牌点击结果(动态)
    private int touchButtonResult = -1;//按钮点击结果(动态)
    private Rect[] pukeLocation; //手牌绘制位置(动态)
    private boolean[] pukeClick;//手牌是否被点击
    private boolean upDraw = true;//第一次绘制(动态)
    private int[] selfPukes;//自身手牌(动态)
    private final int[] threePukes;//地主牌
    private RectF[] button = new RectF[2];//按钮
    private int[] lastPukes = new int[0];//上次出牌
    private String lastName ;//上次出牌玩家名称
    private final Object lock = new Object();//锁
    private Handler recHandler;//消息机制
    private String[] userNames;//所有玩家姓名
    private int selfNameIndex;//自身名称下标
    //myPukeNum 自身手牌数量
    public GameView(Context context, int[] selfPuke, int[] threePuke,String[] userName,int selfNameIndex) {
        super(context);
        holder = getHolder();
        holder.addCallback(this);
        initBitmap();// 实例化图片
        setDeskWH();//设置画布宽高
        selfPukes = selfPuke;//设置自身手牌
        threePukes = threePuke;//设置地主牌
        userNames = userName;//设置所有玩家姓名
        this.selfNameIndex = selfNameIndex;//自身名称下标
        pukeLocation = new Rect[selfPukes.length];//自身牌位置信息
        pukeClick = new boolean[selfPukes.length];//自身牌点击状态
        left_ = getFirstPukeLeft();
        button[0] = new RectF(left_ + 150, (deskHeight - 1.3f * pukeHeight - 130), left_ + 400, (deskHeight - 1.3f * pukeHeight - 30));
        button[1] = new RectF(button[0].right + 150, button[0].top, button[0].right + 400, button[0].bottom);
        //熄屏出现问题
        this.setKeepScreenOn(true);
    }

    private void initBitmap() {// 初始化图片
        sourceBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.small_card);
        pukeWidth = sourceBitmap.getWidth() / 14;// 每张扑克的宽高
        pukeHeight = sourceBitmap.getHeight() / 4;
        Log.i(TAG, "扑克牌宽高: " + pukeWidth + "," + pukeHeight);
        backgroundDesk = BitmapFactory.decodeResource(getResources(),
                R.drawable.gameback2);
        deskWidth = backgroundDesk.getWidth();// 牌桌的宽高
        deskHeight = backgroundDesk.getHeight();
        Log.i(TAG, "背景宽高: " + deskWidth + "," + deskHeight);
        backgroundPuke = BitmapFactory.decodeResource(getResources(),
                R.drawable.cardback);
        sourcePersonBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.person);
        personWidth = sourcePersonBitmap.getWidth() / 3;
        personHeight = sourcePersonBitmap.getHeight();
    }

    /**
     * 绘制开始
     */
    private void PaintDDZ() {
        Canvas canvas = null;
        try {
            canvas = holder.lockCanvas();
            canvas.drawBitmap(backgroundDesk, 0, 0, null);
            PaintThreePuke(canvas);
            PaintPerson(canvas);
            PaintButton(canvas);
            PaintPersonPuke(canvas);
            PaintLastCard(canvas);
        } catch (Exception ignored) {
        } finally {
            //当画布内容不为空时，才post，避免出现黑屏的情况。
            if (canvas != null)
                holder.unlockCanvasAndPost(canvas);
        }
    }


    /**
     * 绘制人物手牌
     *
     * @param canvas 画布
     */
    private void PaintPersonPuke(Canvas canvas) {
        Rect src;
        Rect dst = new Rect();
        // 左手边玩家，不用绘出正面
        // src = person.cardRect(person.person1[j], pukeWidth,
        // pukeHeight);
        // dst.set(10, j * 20, 10 + pukeWidth, j * 20 + pukeHeight);
        canvas.drawBitmap(backgroundPuke, 35, deskHeight / 2 - pukeHeight / 2, null);
        // 右手边玩家，同样不用绘出正面
        // src = person.cardRect(person.person3[j], pukeWidth,
        // pukeHeight);
        // dst.set(this.screenWidth - 10 - pukeWidth, j * 20,
        // this.screenWidth - 10, j * 20 + pukeHeight);
        canvas.drawBitmap(backgroundPuke, deskWidth - 35 - pukeWidth,
                deskHeight / 2 - pukeHeight / 2, null);
        synchronized (lock) {
            // 遍历数组
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < selfPukes.length; j++) {
                    if (i == 1) {// 自己
                        src = Utils.cardRect(selfPukes[j], pukeWidth,
                                pukeHeight);
//                    dst.set(left, deskHeight - pukeHeight * 8 / 5,
//                            left + pukeWidth, deskHeight - pukeHeight * 8 / 5 + pukeHeight);
                        if (upDraw) {
                            dst.set(left_ + (int) (j * a * pukeWidth), (int) (deskHeight - 1.3 * pukeHeight), left_ + (int) (j * a * pukeWidth + pukeWidth), (int) (deskHeight - 0.3 * pukeHeight));
                            pukeLocation[j] = new Rect(left_ + (int) (j * a * pukeWidth), (int) (deskHeight - 1.3 * pukeHeight), left_ + (int) (j * a * pukeWidth + pukeWidth), (int) (deskHeight - 0.3 * pukeHeight));
                            pukeClick[j] = false;
                        } else {
                            dst.set(pukeLocation[j].left, pukeLocation[j].top, pukeLocation[j].right, pukeLocation[j].bottom);
                        }
                        canvas.drawBitmap(sourceBitmap, src, dst, null);
                    }
                }
            }
        }
        upDraw = false;
    }

    /**
     * 绘制地主牌
     *
     * @param canvas 画布
     */
    private void PaintThreePuke(Canvas canvas) {
        Rect src;
        Rect dst = new Rect();
        for (int i = 0; i < 3; i++) {
            src = Utils.cardRect(threePukes[i], pukeWidth, pukeHeight);
            dst.set(deskWidth / 2 - (int) (1.5 * pukeWidth) + i * pukeWidth, 12, deskWidth / 2 - (int) (1.5 * pukeWidth) + (i + 1) * pukeWidth, 12 + pukeHeight);
            canvas.drawBitmap(sourceBitmap, src, dst, null);
        }
    }

    /**
     * 绘制点击按钮
     *
     * @param canvas 画布
     */
    private void PaintButton(Canvas canvas) {
        Paint p = new Paint();
        p.setStyle(Paint.Style.STROKE);//充满
        p.setColor(Color.RED);
        p.setAlpha(200);
        p.setTextSize(30.0f);
        p.setAntiAlias(true);// 设置画笔的锯齿效果
        p.setTextAlign(Paint.Align.CENTER);
        canvas.drawRoundRect(button[0], 20, 10, p);//第二个参数是x半径，第三个参数是y半径
        Paint.FontMetrics fontMetrics = p.getFontMetrics();
        float baseline = (button[0].bottom + button[0].top - fontMetrics.bottom - fontMetrics.top) / 2;
        canvas.drawText("出牌", button[0].centerX(), baseline, p);

        baseline = (button[1].bottom + button[1].top - fontMetrics.bottom - fontMetrics.top) / 2;
        canvas.drawRoundRect(button[1], 20, 10, p);//第二个参数是x半径，第三个参数是y半径
        canvas.drawText("不出", button[1].centerX(), baseline, p);
    }

    /**
     * 绘制人物及名称
     *
     * @param canvas 画布
     */
    private void PaintPerson(Canvas canvas) {
        Rect src = new Rect();
        Rect dst = new Rect();
        Paint p = new Paint();
        p.setColor(Color.RED);
        p.setTextSize(40.0f);
        p.setAntiAlias(true);// 设置画笔的锯齿效果
        switch (selfNameIndex){
            case 0:
                //绘制自身
                src.set(2 * personWidth, 0, 3 * personWidth, personHeight);
                dst.set(35, (int) (deskHeight - 1.3 * pukeHeight), 35 + pukeWidth, (int) (deskHeight - 0.3 * pukeHeight));
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[0],35, (int) (deskHeight - 1.3 * pukeHeight) - p.getFontSpacing(),p);
                //绘制右人物
                src.set(personWidth, 0, 2 * personWidth, personHeight);
                dst.set(deskWidth - 35 - pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight, deskWidth - 35, deskHeight / 2 - pukeHeight / 2 - 10);
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[1],deskWidth - 35 - pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight - p.getFontSpacing(),p);
                //绘制左人物
                src.set(0, 0, personWidth, personHeight);
                dst.set(35, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight, 35 + pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10);
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[2],35, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight - p.getFontSpacing(),p);
                break;
            case 1:
                //绘制自身
                src.set(personWidth, 0, 2 * personWidth, personHeight);
                dst.set(35, (int) (deskHeight - 1.3 * pukeHeight), 35 + pukeWidth, (int) (deskHeight - 0.3 * pukeHeight));
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[1],35, (int) (deskHeight - 1.3 * pukeHeight) - p.getFontSpacing(),p);
                //绘制右人物
                src.set(0, 0, personWidth, personHeight);
                dst.set(deskWidth - 35 - pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight, deskWidth - 35, deskHeight / 2 - pukeHeight / 2 - 10);
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[2],deskWidth - 35 - pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight - p.getFontSpacing(),p);
                //绘制左人物
                src.set(2 * personWidth, 0, 3 * personWidth, personHeight);
                dst.set(35, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight, 35 + pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10);
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[0],35, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight - p.getFontSpacing(),p);
                break;
            case 2:
                //绘制自身
                src.set(0, 0, personWidth, personHeight);
                dst.set(35, (int) (deskHeight - 1.3 * pukeHeight), 35 + pukeWidth, (int) (deskHeight - 0.3 * pukeHeight));
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[2],35, (int) (deskHeight - 1.3 * pukeHeight) - p.getFontSpacing(),p);
                //绘制右人物
                src.set(2 * personWidth, 0, 3 * personWidth, personHeight);
                dst.set(deskWidth - 35 - pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight, deskWidth - 35, deskHeight / 2 - pukeHeight / 2 - 10);
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[0],deskWidth - 35 - pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight - p.getFontSpacing(),p);
                //绘制左人物
                src.set(personWidth, 0, 2 * personWidth, personHeight);
                dst.set(35, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight, 35 + pukeWidth, deskHeight / 2 - pukeHeight / 2 - 10);
                canvas.drawBitmap(sourcePersonBitmap, src, dst, null);
                canvas.drawText(userNames[1],35, deskHeight / 2 - pukeHeight / 2 - 10 - pukeHeight - p.getFontSpacing(),p);
                break;
        }
    }

    /**
     * 绘制玩家上一次出牌及名称
     *
     * @param canvas 画布
     */
    private void PaintLastCard(Canvas canvas) {
        if (lastPukes.length == 0 || lastName == null) {
            return;
        }
        Rect src;
        Rect dst = new Rect();
        Paint p = new Paint();
        p.setColor(Color.RED);
        p.setTextSize(40.0f);
        p.setAntiAlias(true);// 设置画笔的锯齿效果
        //left 用来出牌的左移位置
        int left = (int) (deskWidth - ((lastPukes.length - 1) * pukeWidth * a + pukeWidth)) / 2;// 自身手牌持牌左距 16=17-1 19=20-1
        for (int i = 0; i < lastPukes.length; i++) {
            src = Utils.cardRect(lastPukes[i], pukeWidth,
                    pukeHeight);
            dst.set((int) (left + i * a * pukeWidth), deskHeight / 2 - pukeHeight / 2, left + (int) (i * a * pukeWidth + pukeWidth), deskHeight / 2 - pukeHeight / 2 + pukeHeight);
            canvas.drawBitmap(sourceBitmap, src, dst, null);
        }
        canvas.drawText(lastName,left,deskHeight / 2 - pukeHeight / 2 - p.getFontSpacing(),p);
    }

    /**
     * 设置GameView 画布实际宽高
     */
    private void setDeskWH() {
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        int width = wm.getDefaultDisplay().getWidth();
        int height = wm.getDefaultDisplay().getHeight();
        deskHeight = deskHeight > height ? height : deskHeight;
        deskWidth = deskWidth > width ? width : deskWidth;
    }

    /**
     * 获得自身第一张手牌居左距离
     *
     * @return 距离
     */
    private int getFirstPukeLeft() {
        return (int) (deskWidth - ((selfPukes.length - 1) * pukeWidth * a + pukeWidth)) / 2;// 自身手牌持牌左距 16=17-1 19=20-1
    }


    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            touchPukeResult = PukeClickUtils.isTouchPointInPukes(pukeLocation, event, (int) ((1 - a) * pukeWidth));
            touchButtonResult = PukeClickUtils.isTouchButton(button, event);
        }
        if (event.getAction() == MotionEvent.ACTION_UP) {
//            Toast.makeText(getContext(), ""+touchPukeResult, Toast.LENGTH_SHORT).show();
            //更新手牌位置
            updatePukeLocation(touchPukeResult);
            //是否能够出牌
            updatePlayDraw(touchButtonResult);
        }
        return true;
    }

    /**
     * 更新手牌位置
     *
     * @param result 手牌索引
     */
    private void updatePukeLocation(int result) {
        if (result == -1) {
            return;
        }
        for (int j = 0; j < selfPukes.length; j++) {
            int rise;
            if (result == j) {
                rise = pukeClick[j] ? 20 : -20;
                pukeClick[j] = !pukeClick[j];
                pukeLocation[j].top = pukeLocation[j].top + rise;
                pukeLocation[j].bottom = pukeLocation[j].bottom + rise;
                return;
            }
        }
    }

    /**
     * 更新出牌结果
     * 需要更新
     * pukeLocation    //手牌绘制位置
     * pukeClick       //手牌是否被点击
     * selfPukes       //自身手牌
     *
     * @param touchButtonResult 按钮索引
     */
    private void updatePlayDraw(int touchButtonResult) {
        if (touchButtonResult == -1 || touchButtonResult == 1) {
            return;
        }
        int index = 0;
        List<Integer> clickList = new ArrayList<>();
        for (boolean aPukeClick : pukeClick) {
            index++;
            if (aPukeClick) {
                clickList.add(index);
            }
        }
        //没有点击待出牌
        if (clickList.size() == 0) {
            Toast.makeText(getContext(), "请点击你要出的牌", Toast.LENGTH_SHORT).show();
            return;
        }
        //出牌的索引+
        Integer[] a = new Integer[clickList.size()];
        clickList.toArray(a);
        int b[] = updateLastPuke(clickList.size(), a);
        if (!isCanPlay(b)) {
            Toast.makeText(getContext(), "出牌不符合规则", Toast.LENGTH_SHORT).show();
            return;
        }
        //脏数据更新
        synchronized (lock) {
            //更新上一次出牌
            lastPukes = b;
            lastName = userNames[selfNameIndex];
            //更新手牌
            int[] c = updateSelfPuke(selfPukes.length, clickList.size(), clickList.toArray(a));
            //向服务器发送出牌信息
            Message message = new Message();
            message.what = 2;
            //发送玩家名称和出牌值
            message.obj = userNames[selfNameIndex]+":"+Utils.ArrayIntToString(lastPukes);
            Log.i(TAG, "updatePlayDraw: " + Utils.ArrayIntToString(lastPukes));
            recHandler.sendMessage(message);
            selfPukes = c;
            //更新手牌位置容量
            pukeLocation = new Rect[pukeLocation.length - clickList.size()];
            //更新手牌点击容量
            pukeClick = new boolean[pukeClick.length - clickList.size()];
            //第一次绘制
            upDraw = true;
            //更新第一张手牌左距离
            left_ = getFirstPukeLeft();
        }
    }

    /**
     * 更新手牌
     *
     * @param formerSelfPukesLength 原先手牌长度
     * @param playNum               出牌长度
     * @param playIndex             出牌索引
     * @return 新的手牌
     */
    private int[] updateSelfPuke(int formerSelfPukesLength, int playNum, Integer[] playIndex) {
        int[] selfPukes = new int[formerSelfPukesLength - playNum];
        for (Integer aPlayIndex : playIndex) {
            this.selfPukes[aPlayIndex - 1] = -1;
        }
        for (int i = 0, j = 0; i < this.selfPukes.length; i++) {
            if (this.selfPukes[i] == -1) {
                continue;
            }
            selfPukes[j] = this.selfPukes[i];
            j++;
        }
        return selfPukes;
    }

    /**
     * 更新出牌结果
     *
     * @param playNum   出牌数量
     * @param playIndex 出牌索引
     * @return 新的出牌结果
     */
    private int[] updateLastPuke(int playNum, Integer[] playIndex) {
        int[] lastPuke = new int[playNum];
        int i = 0;
        for (Integer aPlayIndex : playIndex) {
            lastPuke[i] = selfPukes[aPlayIndex - 1];
            i++;
        }
        return lastPuke;
    }

    /**
     * 判断是否可以出牌
     *
     * @return
     */
    private boolean isCanPlay(final int[] a) {
        //出牌符合出牌逻辑
        if (Utils.accordPutLogic(a)) {
            //如果上一次出牌长度为0
            if (lastPukes.length == 0) {
                return true;
            }
            //出牌结果大于上一次出牌结果
            return true;
        }
        return false;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isDrawing = true;
        new Thread(this).start();
        //监管线程
        new Thread(new Regulator()).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isDrawing = false;
        if (sourceBitmap != null && !sourceBitmap.isRecycled()) {
            sourceBitmap.recycle();
            sourceBitmap = null;
        }
        if (backgroundDesk != null && !backgroundDesk.isRecycled()) {
            backgroundDesk.recycle();
            backgroundDesk = null;
        }
        if (backgroundPuke != null && !backgroundPuke.isRecycled()) {
            backgroundPuke.recycle();
            backgroundPuke = null;
        }
        if (sourcePersonBitmap != null && !sourcePersonBitmap.isRecycled()) {
            sourcePersonBitmap.recycle();
            sourcePersonBitmap = null;
        }
        System.gc();
    }

    /**
     * 绘画主线程
     */
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        while (isDrawing) {
            PaintDDZ();
            long end = System.currentTimeMillis();
            if (end - start < 100) {
                try {
                    Thread.sleep(100 - end + start);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 裁判线程 判断游戏是否结束
     */
    private class Regulator implements Runnable {
        @Override
        public void run() {
            while (isDrawing) {
                if (selfPukes.length == 0) {
                    synchronized (lock) {
                        isDrawing = false;
                        //向服务器发送游戏正常结束
                        recHandler.sendEmptyMessage(1);
                    }
                }
            }
        }
    }

    /**
     * 发送服务器线程handler置入view中
     *
     * @param recHandler
     */
    public void setHandler(Handler recHandler) {
        this.recHandler = recHandler;
    }

    /**
     * 更新来自服务器消息
     */
    public void receiveServerToUpdate(String s) {
        //更新最后一次出牌
        synchronized (lock) {
            lastPukes = Utils.StringToArrayInt(s.split(":")[1]);
            lastName = s.split(":")[0];
        }

    }

}